package com.hulk.rpc.utils.concurrent;

import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.concurrent.FastThreadLocalThread;
import io.netty.util.internal.InternalThreadLocalMap;

import java.util.function.Supplier;

/**
 * 当线程为FastThreadLocalThread时能达到ThreadLocal 1.5x的性能；<br>
 * 当线程不满足上述两种情况，将只能达到ThreadLocal 0.7x的性能；<br>
 */
public final class AttachmentThreadUtils {

  private static ThreadLocal<IntObjectHashMap<Object>> SLOW_THREAD_LOCAL_HOLDER
          = ThreadLocal.withInitial(IntObjectHashMap::new);

  /**
   * 寻找下一个线程本地变量位置
   */
  public static int nextVarIndex() {
    return InternalThreadLocalMap.nextVariableIndex();
  }

  /**
   * @param index    通过 {@link #nextVarIndex()} 获得
   * @param producer 尽量使用final常量以获得更好的性能
   */
  @SuppressWarnings("unchecked")
  public static <T> T getOrUpdate(int index, Supplier<T> producer) {
    Thread currentThread = Thread.currentThread();

    if (currentThread instanceof FastThreadLocalThread) {// 很快，1.5x ThreadLocal性能
      FastThreadLocalThread fastThread = (FastThreadLocalThread) currentThread;
      InternalThreadLocalMap threadLocalMap = fastThread.threadLocalMap();

      if (threadLocalMap == null) {
        // 会自动赋值的
        threadLocalMap = InternalThreadLocalMap.get();
      }

      Object obj = threadLocalMap.indexedVariable(index);
      if (obj != InternalThreadLocalMap.UNSET) {
        return (T) obj;
      }

      obj = producer.get();
      threadLocalMap.setIndexedVariable(index, obj);

      return (T) obj;
    }

    {
      IntObjectHashMap<Object> varMap = SLOW_THREAD_LOCAL_HOLDER.get();
      Object obj = varMap.get(index);

      if (obj == null) {
        obj = producer.get();
        varMap.put(index, obj);
      }
      return (T) obj;
    }
  }

  /**
   * @param index 通过 {@link #nextVarIndex()} 获得
   */
  @SuppressWarnings("unchecked")
  public static <T> T get(int index) {
    Thread currentThread = Thread.currentThread();

    if (currentThread instanceof FastThreadLocalThread) {// 很快，1.5x ThreadLocal性能

      FastThreadLocalThread fastThread = (FastThreadLocalThread) currentThread;
      InternalThreadLocalMap threadLocalMap = fastThread.threadLocalMap();

      if (threadLocalMap == null) {
        // 会自动赋值的
        threadLocalMap = InternalThreadLocalMap.get();
      }

      Object obj = threadLocalMap.indexedVariable(index);
      if (obj != InternalThreadLocalMap.UNSET) {
        return (T) obj;
      } else {
        return null;
      }
    }

    {
      IntObjectHashMap<Object> varMap = SLOW_THREAD_LOCAL_HOLDER.get();
      return (T) varMap.get(index);
    }
  }

  /**
   * @param index 通过 {@link #nextVarIndex()} 获得
   */
  public static <T> void put(int index, T value) {
    Thread currentThread = Thread.currentThread();

    if (currentThread instanceof FastThreadLocalThread) {// 很快，1.5x ThreadLocal性能
      FastThreadLocalThread fastThread = (FastThreadLocalThread) currentThread;
      InternalThreadLocalMap threadLocalMap = fastThread.threadLocalMap();

      if (threadLocalMap == null) {
        // 会自动赋值的
        threadLocalMap = InternalThreadLocalMap.get();
      }

      threadLocalMap.setIndexedVariable(index, value);
      return;
    }

    {
      IntObjectHashMap<Object> varMap = SLOW_THREAD_LOCAL_HOLDER.get();
      varMap.put(index, value);
    }
  }

}
